/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Copyright 2002-2003 by Mark Wolgemuth, All rights reserved.             */
/* Copyright 2002-2003 by Employease, Inc.  All rights reserved.           */
/*                                                                         */
/* Redistribution and use in source and binary forms, with or without      */
/* modification, are permitted provided that the following conditions      */
/* are met:                                                                */
/*                                                                         */
/*    1. Redistributions of source code must retain the above copyright    */
/* notice, this list of conditions and the following disclaimer.           */
/*    2. Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the     */
/* documentation and/or other materials provided with the distribution.    */
/*                                                                         */
/* THIS SOFTWARE IS PROVIDED BY THE MOD_ATHENA PROJECT ``AS IS'' AND ANY   */
/* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE       */
/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR      */
/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR        */
/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,   */
/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,     */
/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR      */
/* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT            */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE   */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.    */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "ath_lb.h"
#include "apr_hash.h"

/* host string to obj hash cache */
static apr_hash_t *_cache = NULL;
static apr_pool_t *_cache_ppool = NULL;
static apr_pool_t *_cache_pool = NULL;

typedef struct ath_phys_cache ath_phys_cache;
struct ath_phys_cache {
    ath_phys *phys;
};

/* alloc a phys obj, only used in mirroring */
ath_phys * 
ath_phys_alloc(apr_pool_t *pool)
{
    ath_phys *phys = (ath_phys *) apr_pcalloc(pool, sizeof(ath_phys));
    ASSERT(phys);
    ath_phys_format(phys);
    return phys;
}

/* alloc a phys_cfg obj to be used during apache config */
ath_cfg_phys * 
ath_phys_cfg_alloc(apr_pool_t *pool)
{
    ath_cfg_phys *phys = (ath_cfg_phys *) 
      apr_pcalloc(pool, sizeof(ath_cfg_phys));
    ASSERT(phys);
    phys->host = NULL;
    phys->on = ATH_DEFAULT_STATUS;
    return phys;
}

/* alloc a phys_upd object to be used in /update/phys req */
ath_upd_phys * 
ath_phys_upd_alloc(apr_pool_t *pool)
{
    ath_upd_phys *phys = (ath_upd_phys *) 
      apr_pcalloc(pool, sizeof(ath_upd_phys));
    ASSERT(phys);
    phys->physs = ath_list_ap_alloc(pool);
    phys->on_u = 0;
    phys->up_u = 0;
    phys->cpu_u = 0;
    phys->net_u = 0;
    phys->ld_u = 0;
    phys->mem_u = 0;
    phys->disk_u = 0;
    phys->cus0_u = 0;
    phys->cus1_u = 0;
    phys->cus2_u = 0;
    phys->cus3_u = 0;
    phys->cus4_u = 0;
    phys->cus5_u = 0;
    phys->cus6_u = 0;
    phys->cus7_u = 0;
    phys->cus8_u = 0;
    phys->cus9_u = 0;
    return phys;
}

void
ath_phys_cache_init(apr_pool_t *pool)
{
    apr_pool_t *subpool;
    ASSERT(pool);
    /* always use the same parent pool we started with */
    if (_cache_ppool) 
	ASSERT(_cache_ppool == pool);
    else
	_cache_ppool = pool;
    apr_pool_create(&subpool, _cache_ppool);
    _cache_pool = subpool;
    _cache = apr_hash_make(_cache_pool);
}

void 
ath_phys_cache_expire()
{
    if (_cache)
      {
	  ASSERT(_cache_pool);
	  _cache = NULL;
	  apr_pool_destroy(_cache_pool);
	  _cache_pool = NULL;
      }
}

/* retrieve a phys_cfg by its host name
 * used in farm configuration during startup
 */
ath_cfg_phys * 
ath_phys_cfg_for_host(ath_list *phys_list, const char *host)
{
    int i = 0;
    ath_cfg_phys *phys;
    ath_node *listctx;
    ASSERT(phys_list);
    ASSERT(host);

    ath_list_rewind_r(phys_list, &listctx);
    while (ath_list_hasnext_r(phys_list, &listctx))
      {
	  phys = (ath_cfg_phys *) ath_list_getnext_r(phys_list, &listctx);
	  /* return ptr if match is 0 (true here) */
	  if ((strlen(host) == strlen(phys->host)) 
	      && (!strncmp(phys->host, host, strlen(phys->host))))
	      return phys;
      }
    return NULL;
}

/* formats the initial shm chunk of one phys obj
 * used on startup
 */
void 
ath_phys_format(ath_phys *phys)
{
    int j;
    /* format with no position (this may be alloced phys) */
    phys->idx = ATH_EOA;
    /* write NULL trough hostname field */
    for (j = 0; j < ATH_NAME_MAX; j++)
	phys->host[j] = (int) NULL;
    /* initialize / terminate our farm membership array */
    for (j = 0; j < ATH_FARM_HARDMAX + 1; j++)
	phys->membership_idx[j] = ATH_EOA;
    phys->exists = 0;
    phys->up = ATH_UP;
    phys->on = ATH_ON;
    phys->in = ATH_IN;
    phys->mtime = 0;
    phys->dtime = 0;
    phys->cpu = 0;
    phys->net = 0;
    phys->ld = 0;
    phys->mem = 0;
    phys->disk = 0;
    phys->cus0 = 0;
    phys->cus1 = 0;
    phys->cus2 = 0;
    phys->cus3 = 0;
    phys->cus4 = 0;
    phys->cus5 = 0;
    phys->cus6 = 0;
    phys->cus7 = 0;
    phys->cus8 = 0;
    phys->cus9 = 0;
    phys->lock_idx = ATH_EOA;
}

ath_phys * 
ath_phys_copy(ath_phys *phys_dst, const ath_phys *phys_src)
{
    int j;

    if ((strlen(phys_dst->host) != strlen(phys_src->host))
	|| (strcmp(phys_dst->host, phys_src->host)))
	ath_phys_cache_expire();

    phys_dst->idx = phys_src->idx;
    for (j = 0; j < ATH_NAME_MAX; j++)
	phys_dst->host[j] = phys_src->host[j];
    for (j = 0; j < ATH_FARM_HARDMAX + 1; j++)
	phys_dst->membership_idx[j] = phys_src->membership_idx[j];
    phys_dst->exists = phys_src->exists;
    phys_dst->up = phys_src->up;
    phys_dst->on = phys_src->on;
    phys_dst->in = phys_src->in;
    phys_dst->mtime = phys_src->mtime;
    phys_dst->dtime = phys_src->dtime;
    phys_dst->cpu = phys_src->cpu;
    phys_dst->net = phys_src->net;
    phys_dst->ld = phys_src->ld;
    phys_dst->mem = phys_src->mem;
    phys_dst->disk = phys_src->disk;
    phys_dst->cus0 = phys_src->cus0;
    phys_dst->cus1 = phys_src->cus1;
    phys_dst->cus2 = phys_src->cus2;
    phys_dst->cus3 = phys_src->cus3;
    phys_dst->cus4 = phys_src->cus4;
    phys_dst->cus5 = phys_src->cus5;
    phys_dst->cus6 = phys_src->cus6;
    phys_dst->cus7 = phys_src->cus7;
    phys_dst->cus8 = phys_src->cus8;
    phys_dst->cus9 = phys_src->cus9;
    /* DO NOT COPY LOCK IDX 
     * if this is a real shm phys, it was given a lock_idx on 
     * startup if dst is alloced, then lock not needed or must
     * be manually set
     */
    /*  phys_dst->lock_idx = phys_src->lock_idx; */
    return phys_dst;
}

ath_upd_phys *
ath_phys_upd_clone_stats(ath_upd_phys *dst, ath_upd_phys *src)
{
    ASSERT(dst);
    ASSERT(src);
    dst->on = src->on;
    dst->on_u = src->on_u;
    dst->up = src->up;
    dst->up_u = src->up_u;
    dst->cpu = src->cpu;
    dst->cpu_u = src->cpu_u;
    dst->net = src->net;
    dst->net_u = src->net_u;
    dst->ld = src->ld;
    dst->ld_u = src->ld_u;
    dst->mem = src->mem;
    dst->mem_u = src->mem_u;
    dst->disk = src->disk;
    dst->disk_u = src->disk_u;
    dst->cus0 = src->cus0;
    dst->cus0_u = src->cus0_u;
    dst->cus1 = src->cus1;
    dst->cus1_u = src->cus1_u;
    dst->cus2 = src->cus2;
    dst->cus2_u = src->cus2_u;
    dst->cus3 = src->cus3;
    dst->cus3_u = src->cus3_u;
    dst->cus4 = src->cus4;
    dst->cus4_u = src->cus4_u;
    dst->cus5 = src->cus5;
    dst->cus5_u = src->cus5_u;
    dst->cus6 = src->cus6;
    dst->cus6_u = src->cus6_u;
    dst->cus7 = src->cus7;
    dst->cus7_u = src->cus7_u;
    dst->cus8 = src->cus8;
    dst->cus8_u = src->cus8_u;
    dst->cus9 = src->cus9;
    dst->cus9_u = src->cus9_u;
    return dst;
}

/* maps a phys_cfg to a real phys shm slot 
 * occurs in post_config 
 */
ath_phys * 
ath_phys_configure(ath_phys *phys, ath_cfg_phys *p_cfg, int l_idx)
{
    ath_engine *engine = ath_engine_get();
    ASSERT(phys);
    ASSERT(p_cfg);
    ASSERT(l_idx > -1);

    /* set lock */
    phys->lock_idx = l_idx;
    phys->exists = 1;
    /* set host */
    ath_shm_strncpy(phys->host, p_cfg->host, ATH_NAME_MAX);
    phys->mtime = apr_time_now();
    /* see farm.c ath_farm_cfg_add_member for decision
     * about starting online or offline
     */
    if (p_cfg->on > ATH_EOA)
	phys->on = p_cfg->on;
    else
	phys->on = engine->default_phys_on;
    phys->up = ATH_DEFAULT_STATUS;
    phys->in = ATH_IN;
    engine->phys_count++;
    return phys;
}

/* retrieves phys by its host name, also caches */
ath_phys * 
ath_phys_for_host(const char *host)
{
    int i = 0;
    ath_phys *phys = NULL; 
    ath_engine *engine;

    if (host)
      {
	  if (_cache)
	    {
		ath_phys_cache *cache = (ath_phys_cache *)
		  apr_hash_get(_cache, host, APR_HASH_KEY_STRING);
		if (cache)
		    phys = cache->phys;
	    }
	  else if (_cache_ppool)
	      ath_phys_cache_init(_cache_ppool);
	  
	  if (!phys)
	    {
		engine = ath_engine_get();
		while ((!phys) && (i < engine->phys_count))
		  {
		      phys = ath_phys_for_idx(i);
		      if ((!phys->host)
			  || (strlen(host) != strlen(phys->host)) 
			  || (strncmp(phys->host, host, strlen(phys->host))))
			  phys = NULL;
		      i++;
		  }
		if ((_cache) && (phys))
		  {
		      ath_phys_cache *cache;
		      ASSERT(_cache_pool);
		      cache = apr_pcalloc(_cache_pool, 
					  sizeof(ath_phys_cache));
		      cache->phys = phys;
		      apr_hash_set(_cache, 
				   phys->host, APR_HASH_KEY_STRING, cache);
		  }
	    }
      }
    return phys;
}

ath_phys * 
ath_phys_for_idx(int idx)
{
    ath_phys *phys = ath_phys_raw_for_idx(idx);
    ASSERT(phys);
    if (phys->exists == 1)
	return phys;
    return NULL;
}

ath_phys * 
ath_phys_raw_for_idx(int idx)
{
    ath_phys *phys_base = ath_shm_physbase();
    ath_phys *phys;
    ASSERT(-1 < idx < ATH_PHYS_HARDMAX);
    phys = &phys_base[idx];
    return phys;
}

/* retrieves phys's idx by its host name */
int 
ath_phys_idx_for_host(char *host)
{
    int i = 0;
    ath_phys *phys;
    ASSERT(host);
    
    phys = ath_phys_for_host(host);
    if (phys)
	return phys->idx;
    return ATH_EOA;
}

char * 
ath_phys_to_str(apr_pool_t *p, ath_phys *phys, const char *fmt)
{
    int i, c, idx;
    char *str_out = "";
    ath_farm *farm;
    ASSERT(phys);
    ASSERT(p);
    
    while ((fmt) && (*fmt != (int) NULL))
      {
	  c = (int) *fmt;
	  if  (c == (int) ATH_CASE_ESC)
	    {
		fmt++;
		c = (int) *fmt;
		switch ((char) c)
		  {
		  case ATH_CASE_P_HOST:
		      str_out = apr_pstrcat(p, str_out, phys->host, NULL);
		      break;
		  case ATH_CASE_MTIME:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%"APR_TIME_T_FMT, 
							  phys->mtime)), NULL);
		      break;
		  case ATH_CASE_ON:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%d", 
							  phys->on)), NULL);
		      break;
		  case ATH_CASE_UP:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%d", 
							  phys->up)), NULL);
		      break;
		  case ATH_CASE_IN:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%d", 
							  phys->in)), NULL);
		      break;
		  case ATH_ALGO_CPU:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cpu)), NULL);
		      break;
		  case ATH_ALGO_NET:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->net)), NULL);
		      break;
		  case ATH_ALGO_LOD:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->ld)), NULL);
		      break;
		  case ATH_ALGO_MEM:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->mem)), NULL);
		      break;
		  case ATH_ALGO_DIS:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->disk)), NULL);
		      break;
		  case ATH_ALGO_CU0:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus0)), NULL);
		      break;
		  case ATH_ALGO_CU1:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus1)), NULL);
		      break;
		  case ATH_ALGO_CU2:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus2)), NULL);
		      break;
		  case ATH_ALGO_CU3:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus3)), NULL);
		      break;
		  case ATH_ALGO_CU4:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus4)), NULL);
		      break;
		  case ATH_ALGO_CU5:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus5)), NULL);
		      break;
		  case ATH_ALGO_CU6:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus6)), NULL);
		      break;
		  case ATH_ALGO_CU7:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus7)), NULL);
		      break;
		  case ATH_ALGO_CU8:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus8)), NULL);
		      break;
		  case ATH_ALGO_CU9:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%f", 
							  phys->cus9)), NULL);
		      break;
		  case ATH_CASE_P_MEMB: /* farm memberships */
		      i = 0;
		      while (phys->membership_idx[i] != ATH_EOA)
			{
			    if (phys->membership_idx[i] != ATH_OPN)
			      {
				  idx = phys->membership_idx[i];
				  farm = ath_farm_for_idx(idx);
				  if (farm)
				    {
					if (i == 0)
					    str_out = 
					      apr_pstrcat(p, str_out, 
							  farm->name, NULL);
					else
					    str_out = 
					      apr_pstrcat(p, str_out, " ", 
							  farm->name, NULL);
				    }
			      }
			    i++;
			}
		      break;
		  case ATH_CASE_SERIAL:
		      str_out = 
			apr_pstrcat(p, str_out,
				    apr_psprintf(p, 
						 "%d|%d|%s|%d|%d|%d|%"APR_TIME_T_FMT"|%"APR_TIME_T_FMT
						 "|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|%f|",
						 phys->idx,
						 phys->exists,
						 (phys->host != NULL) ? phys->host : ATH_NULL_STR,
						 phys->on,
						 phys->up,
						 phys->in,
						 phys->mtime,
						 phys->dtime,
						 phys->cpu,
						 phys->net,
						 phys->ld,
						 phys->mem,
						 phys->disk,
						 phys->cus0,
						 phys->cus1,
						 phys->cus2,
						 phys->cus3,
						 phys->cus4,
						 phys->cus5,
						 phys->cus6,
						 phys->cus7,
						 phys->cus8,
						 phys->cus9),
				    NULL);
		      /* for (i = 0; i < engine->farm_count; i++) */
		      for (i = 0; phys->membership_idx[i] != ATH_EOA; i++)
			{
			    str_out = 
			      apr_pstrcat(p, str_out,
					  apr_itoa(p, phys->membership_idx[i]), ",", 
					  NULL);
			}
		      str_out = 
			apr_pstrcat(p, str_out,
				    apr_itoa(p, phys->membership_idx[i]), NULL);
		      /* phys->lock_idx is not serialized */
		      break;
		  default:
		      str_out = apr_pstrcat(p, str_out, 
					    (apr_psprintf(p, "%%%c", (char) c)), NULL);
		  }
	    }
	  else
	    {
		str_out = apr_pstrcat(p, str_out, 
				      (apr_psprintf(p, "%c", (char) c)), NULL);
	    }
	  fmt++;
      }
    return str_out;
}

/* reverses the previous function
 * must be in format generated by previous
 * otherwise very unpredictable results
 * although some validation is done
 */
ath_phys * 
ath_phys_clone_from_str(apr_pool_t *pool, char *str_phys)
{
    char *str_tok1 = NULL;
    char *inter1;
    char *sep1 = "|";
    ath_phys *phys = NULL;
    ath_lock *lock;
    int i;
    int phys_is_valid = 1;
    ath_phys *phys_mirr;
    ASSERT(str_phys);

    /* order is:
     * idx|exists|hostname|on|up|..stats..|farm1,farm2,..
     */
    /* we will work on temporary phys obj to validate */
    phys_mirr = ath_phys_alloc(pool);
    i = 0;
    str_tok1 = apr_strtok(str_phys, sep1, &inter1);
    while ((str_tok1) && (phys_is_valid) && (i < 24))
      {
	  if (i==0) /* idx validity can only be checked in shm */
	      phys_mirr->idx = atoi(str_tok1);
	  else if (i==1)
	      phys_mirr->exists = atoi(str_tok1);
	  else if (i==2)
	      ath_shm_strncpy(phys_mirr->host, str_tok1, strlen(str_tok1));
	  else if (i==3)
	      phys_mirr->on = atoi(str_tok1);
	  else if (i==4)
	      phys_mirr->up = atoi(str_tok1);
	  else if (i==5)
	      phys_mirr->in = atoi(str_tok1);
	  else if (i==6)
	      phys_mirr->mtime = apr_atoi64(str_tok1);
	  else if (i==7)
	      phys_mirr->dtime = apr_atoi64(str_tok1);
	  else if (i==8)
	      phys_mirr->cpu = strtod(str_tok1, NULL);
	  else if (i==9)
	      phys_mirr->net = strtod(str_tok1, NULL);
	  else if (i==10)
	      phys_mirr->ld = strtod(str_tok1, NULL);
	  else if (i==11)
	      phys_mirr->mem = strtod(str_tok1, NULL);
	  else if (i==12)
	      phys_mirr->disk = strtod(str_tok1, NULL);
	  else if (i==13)
	      phys_mirr->cus0 = strtod(str_tok1, NULL);
	  else if (i==14)
	      phys_mirr->cus1 = strtod(str_tok1, NULL);
	  else if (i==15)
	      phys_mirr->cus2 = strtod(str_tok1, NULL);
	  else if (i==16)
	      phys_mirr->cus3 = strtod(str_tok1, NULL);
	  else if (i==17)
	      phys_mirr->cus4 = strtod(str_tok1, NULL);
	  else if (i==18)
	      phys_mirr->cus5 = strtod(str_tok1, NULL);
	  else if (i==19)
	      phys_mirr->cus6 = strtod(str_tok1, NULL);
	  else if (i==20)
	      phys_mirr->cus7 = strtod(str_tok1, NULL);
	  else if (i==21)
	      phys_mirr->cus8 = strtod(str_tok1, NULL);
	  else if (i==22)
	      phys_mirr->cus9 = strtod(str_tok1, NULL);
	  else if (i==23)
	    {
		char *str_tok2 = NULL;
		char *sep2 = ",";
		char *inter2;
		int j = 0;
		str_tok2 = apr_strtok(str_tok1, sep2, &inter2);
		if (str_tok2)
		  { 
		      while (str_tok2 != NULL)
			{
			    phys_mirr->membership_idx[j] = atoi(str_tok2);
			    j++;
			    str_tok2 = apr_strtok(NULL, sep2, &inter2);
			}
		  }
		else
		    phys_is_valid = 0;
	    }
	  i++;
	  str_tok1 = apr_strtok(NULL, sep1, &inter1);
      }

    if ((i < 24) || (!phys_is_valid))
	phys_mirr = NULL;
    return phys_mirr;
}

/* determines if a particular field has been updated 
 * in the phys_upd object
 * used by expect_update when a particular field is required
 */
#define ATH_PHYS_IS_UPD(f, u) ((field == f) && (u == 1))
int 
ath_phys_upd_field_updated(const ath_upd_phys *phys_upd, const char field)
{
    ASSERT(phys_upd);
    ASSERT(field);
    if ATH_PHYS_IS_UPD(ATH_ALGO_CPU, phys_upd->cpu_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_NET, phys_upd->net_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_LOD, phys_upd->ld_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_MEM, phys_upd->mem_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_DIS, phys_upd->disk_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU0, phys_upd->cus0_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU1, phys_upd->cus1_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU2, phys_upd->cus2_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU3, phys_upd->cus3_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU4, phys_upd->cus4_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU5, phys_upd->cus5_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU6, phys_upd->cus6_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU7, phys_upd->cus7_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU8, phys_upd->cus8_u)
	return 1;
    else if ATH_PHYS_IS_UPD(ATH_ALGO_CU9, phys_upd->cus9_u)
	return 1;
    else 
	return 0;
}
